package wangwenjun.phase2.concurrencypattern.eventrouter.demo02;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import util.ThreadUtil;
import wangwenjun.phase2.concurrencypattern.eventrouter.demo02.framework.Channel;
import wangwenjun.phase2.concurrencypattern.eventrouter.demo02.framework.Event;
import wangwenjun.phase2.concurrencypattern.eventrouter.demo02.framework.Router;

import java.util.concurrent.ThreadLocalRandom;

/**
 * @author ChangLiang
 * @date 2020/6/20
 */
@Slf4j
public class AppTest {

    @Test
    @DisplayName("test basic use")
    public void test() {
        log.info("{} start", this.getClass().getSimpleName());
        // 构造Router
        Router router = new Router();
        // 将Event和Handler(Channel)的绑定关系注册到Dispatcher
        router.registerChannel(InputEvent.class, new InputEventValve(router));
        router.registerChannel(OutputEvent.class, new OutputEventValve());
        router.dispatch(new InputEvent(1, 2));
        log.info("{} finish", this.getClass().getSimpleName());
    }

    @Getter
    @AllArgsConstructor
    static class InputEvent extends Event {
        /**
         * InputEvent 是一个Message ， 它包含了两个Int 类型的属性
         */

        private final int x;

        private final int y;
    }

    @Getter
    @AllArgsConstructor
    static class OutputEvent extends Event {
        /**
         * OutputEvent 相对比较简单，
         * 只包含了计算结果的属性，
         */
        private final int result;
    }

    @AllArgsConstructor
    @Slf4j
    static class InputEventValve implements Channel<InputEvent> {

        private final Router router;

        /**
         * 将计算的结果构造成新的Event 提交给Router
         * InputEventValve
         * 是对InputEvent 消息的处理，接收到了InputEvent 消息之后，分别对X 和Y 进行相加操
         * 作，然后将结果封装成OutputEvent 提交给Router
         *
         * @param message
         */
        @Override
        public void dispatch(InputEvent message) {
            ThreadUtil.sleepForMilliSeconds(ThreadLocalRandom.current().nextInt(200,1000));
            log.info("{} process x:{}, y:{}", this.getClass().getSimpleName(), message.getX(), message.getY());
            int result = message.getX() + message.getY();
            // 构造新的Event
            router.dispatch(new OutputEvent(result));
        }
    }


    @Slf4j
    static class OutputEventValve implements Channel<OutputEvent> {

        /**
         * OutputEventValve 则将计算结果输出 相当于是最后一个valve
         */

        @Override
        public void dispatch(OutputEvent message) {
            ThreadUtil.sleepForMilliSeconds(ThreadLocalRandom.current().nextInt(200,1000));
            log.info("{} The result is:{}", this.getClass().getSimpleName(), message.getResult());
        }
    }
}
